﻿using System;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Expressions
{
    partial class BinaryExpression
    {

        private abstract class BinaryExpressionArrayBase: ExpressionArrayBase
        {
            protected readonly BinaryExpression _expression;
            protected readonly EvaluationContext _context;

            protected BinaryExpressionArrayBase(BinaryExpression expression, EvaluationContext context)
            {
                _expression = expression;
                _context = context;
            }

        }

        abstract class CombinedBinaryExpressionArray: BinaryExpressionArrayBase
        {
            protected readonly IArray _leftArray;
            protected readonly IArray _rightArray;
            protected int _rowCount;
            protected int _columnCount;
            public override sealed object this[int row, int column]
            {

                get { return _expression.computedValue(_context, GetLeftValue(row, column), GetRightValue(row, column)); }

            }

            protected abstract object GetLeftValue(int row, int column);
            protected abstract object GetRightValue(int row, int column);


            public CombinedBinaryExpressionArray(BinaryExpression expression, EvaluationContext context, IArray leftArray, IArray rightArray) : base(expression, context)
            {
                Contract.Requires(leftArray != null);
                Contract.Requires(rightArray != null);
                this._leftArray = leftArray;
                this._rightArray = rightArray;
            }

            public override sealed int RowCount
            {
                get { return _rowCount; }
            }

            public override sealed int ColumnCount
            {
                get { return _columnCount; }
            }
        }
        private class LeftCarthesionBinaryExpressionArray : CombinedBinaryExpressionArray
        {
            public LeftCarthesionBinaryExpressionArray(BinaryExpression expression, EvaluationContext context, IArray leftArray, IArray rightArray) :
                base(expression, context, leftArray, rightArray)
            {
                _rowCount = rightArray.RowCount;
                _columnCount = leftArray.ColumnCount;
            }

            protected override object GetLeftValue(int row, int column)
            {
                return _leftArray[0, column];
            }
            protected override object GetRightValue(int row, int column)
            {
                return _rightArray[row, 0];
            }

        }
        private class RightCarthesionBinaryExpressionArray : CombinedBinaryExpressionArray
        {
            public RightCarthesionBinaryExpressionArray(BinaryExpression expression, EvaluationContext context, IArray leftArray, IArray rightArray) :
                base(expression, context, leftArray, rightArray)
            {
                _rowCount = leftArray.RowCount;
                _columnCount = rightArray.ColumnCount;
            }

            protected override object GetLeftValue(int row, int column)
            {
                return _leftArray[row, 0];
            }
            protected override object GetRightValue(int row, int column)
            {
                return _rightArray[0, column];
            }

        }
        private class BinaryExpressionArray : CombinedBinaryExpressionArray
        {

            public BinaryExpressionArray(BinaryExpression expression, EvaluationContext context, IArray leftArray, IArray rightArray) :
                base(expression, context, leftArray, rightArray)
            {
                _rowCount = _leftArray.RowCount;
                _columnCount = _leftArray.ColumnCount;
            }



            protected override object GetLeftValue(int row, int column)
            {
               return  _leftArray[row, column];
            }
            protected override object GetRightValue(int row, int column)
            {
                return _rightArray[row, column];
            }
        }


        private class LeftBinaryExpressionArray: BinaryExpressionArrayBase
        {
            private readonly IArray _leftArray;
            private readonly object _rightValue;

            public LeftBinaryExpressionArray(BinaryExpression expression, EvaluationContext context, IArray leftArray, object rightValue)
                : base(expression, context)
            {
                _leftArray = leftArray;
                _rightValue = rightValue;
            }

            public override object this[int row, int column]
            {
                get { return _expression.computedValue(_context, ArrayExpressionHelper.AccessCell(_leftArray[row, column]), _rightValue); }
            }

            public override int RowCount
            {
                get { return this._leftArray.RowCount; }
            }

            public override int ColumnCount
            {
                get { return _leftArray.ColumnCount; }
            }
        }

        private class RightBinaryExpressionArray: BinaryExpressionArrayBase
        {
            private readonly object _leftValue;
            private readonly IArray _rightArray;

            public RightBinaryExpressionArray(BinaryExpression expression, EvaluationContext context, object leftValue, IArray rightArray) : base(expression, context)
            {
                _leftValue = leftValue;
                _rightArray = rightArray;
            }

            public override object this[int row, int column]
            {
                get { return _expression.computedValue(_context,_leftValue, ArrayExpressionHelper.AccessCell(_rightArray[row, column])); }
            }

            public override int RowCount
            {
                get { return this._rightArray.RowCount; }
            }

            public override int ColumnCount
            {
                get { return _rightArray.ColumnCount; }
            }
        }
    }
}